package com.panghl.config;

import lombok.Getter;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;

/**
 * 文件类型工具
 */
public final class FileTypeUtil {
    /**
     * Constructor
     */
    private FileTypeUtil() {
    }

    /**
     * 将文件头转换成16进制字符串
     *
     * @return 16进制字符串
     */
    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 得到文件头
     *
     * @param filePath 文件路径
     * @return 文件头
     * @throws IOException
     */
    private static String getFileContent(String filePath) throws IOException {
        byte[] b = new byte[28];
        try (InputStream inputStream = new FileInputStream(filePath)) {
            inputStream.read(b, 0, 28);
        }
        return bytesToHexString(b);
    }

    /**
     * 文件流获取文件类型
     *
     * @param file MultipartFile文件流
     * @return
     * @throws IOException
     */
    public static FileTypeEnum getType(MultipartFile file) {
        byte[] b = new byte[28];
        try (InputStream inputStream = file.getInputStream()) {
            inputStream.read(b, 0, 28);
        } catch (IOException e) {
            e.printStackTrace();
            return FileTypeEnum.NULL;
        }
        String fileHead = bytesToHexString(b);

        if (fileHead == null || fileHead.length() == 0) {
            return FileTypeEnum.NULL;
        }
        fileHead = fileHead.toUpperCase();

        FileTypeEnum[] fileTypes = FileTypeEnum.values();

        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        for (FileTypeEnum type : fileTypes) {
            if (fileHead.startsWith(type.getValue().toUpperCase())) {
                return type;
            }
            // 防止部分为 FileTypeEnum.NULL
            if (type.getSuffix().equals(suffix)) {
                return type;
            }
        }
        return FileTypeEnum.NULL;
    }


    /**
     * 判断文件类型
     *
     * @param filePath 文件路径
     * @return 文件类型
     */
    public static FileTypeEnum getType(String filePath) {
        String fileHead = null;
        try {
            fileHead = getFileContent(filePath);
        } catch (IOException e) {
            e.printStackTrace();
            return FileTypeEnum.NULL;
        }

        if (fileHead == null || fileHead.length() == 0) {
            return FileTypeEnum.NULL;
        }
        fileHead = fileHead.toUpperCase();

        FileTypeEnum[] fileTypes = FileTypeEnum.values();
        for (FileTypeEnum type : fileTypes) {
            if (fileHead.startsWith(type.getValue().toUpperCase())) {
                return type;
            }
        }
        return FileTypeEnum.NULL;
    }

    @Getter
    public enum SimpleFileTypeEnum {
        IMAGE("图片", "1"),
        VIDEO("视频", "2"),
        AUDIO("音频", "3"),
        NORMAL("文件", "4"),
        INSTALLATION_PACKAGE("安装包", "5"),
        PDF("pdf", "6"),
        ;

        private String name;
        private String type;

        SimpleFileTypeEnum(String name, String type) {
            this.name = name;
            this.type = type;
        }

        public static boolean canDirectPreview(String fileType) {
            return IMAGE.type.equals(fileType) || PDF.type.equals(fileType);
        }

    }



    public enum FileTypeEnum {

        /**
         * JPEG (jpg)
         **/
        JPG("FFD8FF", ".jpg", "1"),
        /**
         * PNG (png)
         */
        PNG("89504E47", ".png", "1"),
        GIF("47494638", ".gif", "1"), //GIF (gif)
        TIFF("49492A00", ".tif", "1"), //TIFF (tif)
        BMP16("424d228c010000000000", ".bmp", "1"), //16色位图(bmp)
        BMP24("424d8240090000000000", ".bmp", "1"), //24位位图(bmp)
        BMP256("424d8e1b030000000000", ".bmp", "1"), //256色位图(bmp)

        CAD("41433130313500000000", ".dwg", "4"), //CAD (dwg)
        HTML("3c21444f435459504520", ".html", "4"), //HTML (html)
        HTM("3c21646f637479706520", ".htm", "4"), //HTM (htm)
        CSS("48544d4c207b0d0a0942", ".css", "4"), //css
        JS("696b2e71623d696b2e71", ".js", "4"), //js
        RTF("7b5c727466315c616e73", ".rtf", "4"), //Rich Text Format (rtf)
        PSD("38425053000100000000", ".psd", "4"), //Photoshop (psd)
        EML("46726f6d3a203d3f6762", ".eml", "4"), //Email [Outlook Express 6] (eml)
        DOC("d0cf11e0a1b11ae10000", ".doc", "4"), //MS Excel 注意：word、msi 和 excel的文件头一样
        VSD("d0cf11e0a1b11ae10000", ".vsd", "4"), //Visio 绘图
        MDB("5374616E64617264204A", ".mdb", "4"), //MS Access (mdb)
        PS("252150532D41646F6265", ".ps", "4"),
        PDF("255044462D312E", ".pdf", "6"), //Adobe Acrobat (pdf)
        RMVB("2e524d46000000120001", ".rmvb", "2"), //rmvb/rm相同
        FLV("464c5601050000000900", ".flv", "2"), //flv与f4v相同
        MP4("00000020667479706d70", ".mp4", "2"),
        MP3("49443303000000002176", ".mp3", "3"),
        MPG("000001ba210001000180", ".mpg", "3"), //
        WMV("3026b2758e66cf11a6d9", ".wmv", "3"), //wmv与asf相同
        WAV("52494646e27807005741", ".wav", "2"), //Wave (wav)
        AVI("52494646d07d60074156", ".avi", "2"),
        MID("4d546864000000060001", ".mid", "2"), //MIDI (mid)
        ZIP("504b0304140000000800", ".zip", "4"),
        RAR("526172211a0700cf9073", ".rar", "4"),
        INI("235468697320636f6e66", ".ini", "4"),
        JAR("504b03040a0000000000", ".jar", "4"),
        EXE("4d5a9000030000000400", ".exe", "5"),//可执行文件
        JSP("3c25402070616765206c", ".jsp", "4"),//jsp文件
        MF("4d616e69666573742d56", ".mf", "4"),//MF文件
        XML("3c3f786d6c2076657273", ".xml", "4"),//xml文件
        SQL("494e5345525420494e54", ".sql", "4"),//xml文件
        JAVA("7061636b616765207765", ".java", "4"),//java文件
        BAT("406563686f206f66660d", ".bat", "4"),//bat文件
        GZ("1f8b0800000000000000", ".gz", "4"),//gz文件
        PROPERTIES("6c6f67346a2e726f6f74", ".properties", "4"),//bat文件
        CLASS("cafebabe0000002e0041", ".class", "4"),//bat文件
        CHM("49545346030000006000", ".chm", "4"),//bat文件
        MXP("04000000010000001300", ".mxp", "4"),//bat文件
        DOCX("504b0304140006000800", ".docx", "4"),//docx文件
        WPS("d0cf11e0a1b11ae10000", ".wps", "4"),//WPS文字wps、表格et、演示dps都是一样的
        TORRENT("6431303a637265617465", ".torrent", "4"),
        MOV("6D6F6F76", ".mov", "4"), //Quicktime (mov)
        WPD("FF575043", ".wpd", "4"), //WordPerfect (wpd)
        DBX("CFAD12FEC5FD746F", ".dbx", "4"), //Outlook Express (dbx)
        PST("2142444E", ".pst", "4"), //Outlook (pst)
        QDF("AC9EBD8F", ".qdf", "4"), //Quicken (qdf)
        PWL("E3828596", ".pwl", "4"), //Windows Password (pwl)
        RAM("2E7261FD", ".ram", "4"), //Real Audio (ram)
        NULL("未知", ".*", "4"); //Real Audio (ram)

        private String value;
        private String suffix;
        /**
         * 1 图片
         * 2 视频
         * 3 音频
         * 4 文件 (默认)
         * 5 安装包
         * 6 pdf
         */
        private String fileType;


        FileTypeEnum(String value, String suffix, String fileType) {
            this.value = value;
            this.suffix = suffix;
            this.fileType = fileType;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public String getSuffix() {
            return suffix;
        }

        public void setSuffix(String suffix) {
            this.suffix = suffix;
        }

        public String getFileType() {
            return fileType;
        }

        public void setFileType(String fileType) {
            this.fileType = fileType;
        }

        public static FileTypeEnum valueToEnum(String value) {
            for (FileTypeEnum fileTypeEnum : FileTypeEnum.values()) {
                if (Objects.equals(value, fileTypeEnum.getValue())) {
                    return fileTypeEnum;
                }
            }
            return null;
        }
    }
}
